home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / utils / trace.c < prev    next >
C/C++ Source or Header  |  1991-06-27  |  10KB  |  383 lines

  1. /* 
  2.  * trace.c --
  3.  *
  4.  *    This files implements a generalized tracing facility.  A Trace_Buffer
  5.  *    contains information about the number and size of the elements in a
  6.  *    circular buffer that is dynamically allocated by Trace_Init.  Calls
  7.  *    to Trace_Insert add a time-stamped trace record to the buffer.
  8.  *    A circular buffer of trace records can be dumped to a file via calls
  9.  *    to Trace_Dump.
  10.  *
  11.  * Copyright 1986 Regents of the University of California
  12.  * Permission to use, copy, modify, and distribute this
  13.  * software and its documentation for any purpose and without
  14.  * fee is hereby granted, provided that this copyright
  15.  * notice appears in all copies.  The University of California
  16.  * makes no representations about the suitability of this
  17.  * software for any purpose.  It is provided "as is" without
  18.  * express or implied warranty.
  19.  */
  20.  
  21. #ifndef lint
  22. static char rcsid[] = "$Header: /sprite/src/kernel/utils/RCS/trace.c,v 9.3 91/06/27 12:16:11 shirriff Exp $ SPRITE (Berkeley)";
  23. #endif not lint
  24.  
  25.  
  26. #include "sprite.h"
  27. #include "trace.h"
  28. #include "bstring.h"
  29. #include "timer.h"
  30. #include "stdlib.h"
  31. #include "sys.h"
  32. #include "sync.h"
  33. #include "vm.h"
  34. #include <stdio.h>
  35.  
  36. /* 
  37.  * Trace module mutex.
  38.  */
  39.  
  40. Sync_Semaphore trace_Mutex = Sync_SemInitStatic("Utils:trace_Mutex");
  41.  
  42. /*
  43.  * Global tracing inhibit flag so it is easy to turn off all system tracing.
  44.  */
  45. Boolean trace_Disable = FALSE;
  46.  
  47.  
  48. /*
  49.  *----------------------------------------------------------------------
  50.  *
  51.  * Trace_Init --
  52.  *
  53.  *    Allocate and initialize a circular trace buffer.
  54.  *
  55.  * Results:
  56.  *    None.
  57.  *
  58.  * Side effects:
  59.  *    Memory is allocated for the individual buffer records.  Note 
  60.  *    that the Trace_Header is assumed to be allocated
  61.  *    (statically or dynamically) by the calling routine, and its values
  62.  *    are initialized in this routine.
  63.  *
  64.  *----------------------------------------------------------------------
  65.  */
  66.  
  67. void
  68. Trace_Init(traceHdrPtr, numRecords, size, flags)
  69.     register Trace_Header *traceHdrPtr;    /* pointer to tracing info */
  70.     int numRecords;            /* number of records to allocate */
  71.     int size;                /* size of each client-specific area */
  72.     int flags;                /* TRACE_NO_TIMES */
  73. {
  74.     register Address clientPtr;
  75.     register Trace_Record *recordPtr;
  76.     int i;
  77.  
  78.  
  79.     traceHdrPtr->numRecords = numRecords;
  80.     traceHdrPtr->currentRecord = 0;
  81.     traceHdrPtr->flags = flags & ~TRACE_INHIBIT;
  82.     traceHdrPtr->dataSize = size;
  83.  
  84.     recordPtr = (Trace_Record *) Vm_RawAlloc(numRecords * sizeof(Trace_Record));
  85.     traceHdrPtr->recordArray = recordPtr;
  86.  
  87.     if (size > 0) {
  88.     clientPtr = Vm_RawAlloc(numRecords * size);
  89.     } else {
  90.     clientPtr = (Address) NIL;
  91.     }
  92.     for (i = 0; i < numRecords; i++) {
  93.     recordPtr[i].flags = TRACE_UNUSED;
  94.     recordPtr[i].event = NIL;
  95.     recordPtr[i].traceData = (ClientData *) clientPtr;
  96.     if (size > 0) {
  97.         clientPtr += size;
  98.     }
  99.     }
  100. }
  101.  
  102.  
  103. /*
  104.  *----------------------------------------------------------------------
  105.  *
  106.  * Trace_Insert --
  107.  *
  108.  *    Save a time stamp and any client-specific data in a circular buffer.
  109.  *
  110.  * Results:
  111.  *    None.
  112.  *
  113.  * Side effects:
  114.  *    Record the information in a trace record and advance the
  115.  *    circular buffer pointer.
  116.  *
  117.  *----------------------------------------------------------------------
  118.  */
  119. void
  120. Trace_Insert(traceHdrPtr, event, data)
  121.     Trace_Header *traceHdrPtr;
  122.     int event;
  123.     ClientData data;
  124. {
  125.     Trace_Record *recordPtr;
  126.     int size;
  127.     Timer_Ticks ticks;
  128.  
  129.     if (trace_Disable) {
  130.     return;
  131.     }
  132.     MASTER_LOCK(&trace_Mutex);
  133.     Sync_SemRegister(&trace_Mutex);
  134.     if (traceHdrPtr == (Trace_Header *)NIL ||
  135.     (traceHdrPtr->flags & TRACE_INHIBIT)) {
  136.     MASTER_UNLOCK(&trace_Mutex);
  137.     return;
  138.     }
  139.  
  140.     recordPtr = &(traceHdrPtr->recordArray[traceHdrPtr->currentRecord]);
  141.     if ( ! (traceHdrPtr->flags & TRACE_NO_TIMES)) {
  142.     Timer_GetCurrentTicks(&ticks);
  143.     Timer_TicksToTime(ticks, &(recordPtr->time));
  144.     }
  145.     size = traceHdrPtr->dataSize;
  146.     if ((size > 0) && (data != (ClientData) NIL)) {
  147.     bcopy((Address) data, (Address) recordPtr->traceData,size);
  148.     recordPtr->flags = TRACE_DATA_VALID;
  149.     } else {
  150.     if (recordPtr->traceData != (ClientData *) NIL) {
  151.         bzero((Address) recordPtr->traceData,size);
  152.     }
  153.     recordPtr->flags = TRACE_DATA_INVALID;
  154.     }
  155.     recordPtr->event = event;
  156.     traceHdrPtr->currentRecord =
  157.         (traceHdrPtr->currentRecord + 1) % traceHdrPtr->numRecords;
  158.     MASTER_UNLOCK(&trace_Mutex);
  159. }
  160.  
  161.  
  162. /*
  163.  *----------------------------------------------------------------------
  164.  *
  165.  * Trace_Dump --
  166.  *
  167.  *    Dump trace records into the user's address space.  Data is copied
  168.  *    in the following order:
  169.  *
  170.  *    (1) The number of records being copied is copied.
  171.  *    (2) numRecs Trace_Records are copied.
  172.  *    (3) If traceData is non-NIL, numRecs records of traceData are copied.
  173.  *
  174.  * Results:
  175.  *    The result from Vm_CopyOut is returned, in addition to the
  176.  *    data specified above.
  177.  *
  178.  * Side effects:
  179.  *    Data is copied out to the user's address space.
  180.  *
  181.  *----------------------------------------------------------------------
  182.  */
  183.  
  184. ReturnStatus
  185. Trace_Dump(traceHdrPtr, numRecs, addr)
  186.     register Trace_Header *traceHdrPtr;
  187.     int numRecs;
  188.     Address addr;
  189. {
  190.     ReturnStatus status;
  191.     int size;
  192.     int earlyRecs = 0;
  193.     int lateRecs;
  194.     int current;
  195.  
  196.     if (traceHdrPtr == (Trace_Header *) NIL) {
  197.     printf("Trace_Dump: trace buffer not initialized.\n");
  198.     numRecs = 0;
  199.     status = Vm_CopyOut(sizeof(int), (Address) &numRecs, addr);
  200.     return(status);
  201.     }
  202.     if (trace_Disable) {
  203.     printf("Trace_Dump: all tracing disabled.\n");
  204.     numRecs = 0;
  205.     status = Vm_CopyOut(sizeof(int), (Address) &numRecs, addr);
  206.     return(status);
  207.     }
  208.  
  209.     MASTER_LOCK(&trace_Mutex);
  210.     traceHdrPtr->flags |= TRACE_INHIBIT;
  211.     MASTER_UNLOCK(&trace_Mutex);
  212.  
  213.     if (numRecs > traceHdrPtr->numRecords) {
  214.     numRecs = traceHdrPtr->numRecords;
  215.     }
  216.  
  217.     /*
  218.      * Check the current record to see if it's unused.  If so, then all
  219.      * records before it are valid and all records after it are invalid,
  220.      * since once we wrap around once all records are used forever.
  221.      */
  222.     
  223.     current = traceHdrPtr->currentRecord;
  224.     lateRecs = traceHdrPtr->numRecords - current;
  225.     if (traceHdrPtr->recordArray[current].flags == TRACE_UNUSED) {
  226.     numRecs = current;
  227.     earlyRecs = current;
  228.     lateRecs = 0;
  229.     } else if (numRecs > lateRecs) {
  230.     earlyRecs = numRecs - lateRecs;
  231.     }
  232.     
  233.     status = Vm_CopyOut(sizeof(int), (Address) &numRecs, addr);
  234.     if (status != SUCCESS || numRecs == 0) {
  235.     goto done;
  236.     }
  237.     addr += sizeof(int);
  238.  
  239.     /*
  240.      * Copy the general trace records.  First copy the ones from "current"
  241.      * to the end of the buffer, then copy the ones at the front.
  242.      */
  243.  
  244.     if (lateRecs > 0) {
  245.     size = lateRecs * sizeof(Trace_Record);
  246.     status = Vm_CopyOut(size, (Address) &traceHdrPtr->recordArray[current],
  247.                 addr);
  248.     if (status != SUCCESS) {
  249.         goto done;
  250.     }
  251.     addr += size;
  252.     }
  253.     if (earlyRecs > 0) {
  254.     size = earlyRecs * sizeof(Trace_Record);
  255.     status = Vm_CopyOut(size, (Address) &traceHdrPtr->recordArray[0],
  256.                 addr);
  257.     if (status != SUCCESS) {
  258.         return(status);
  259.     }
  260.     addr += size;
  261.     }
  262.  
  263.     /*
  264.      * Copy the client-specific data, if there is any.
  265.      */
  266.     
  267.     if (traceHdrPtr->dataSize == 0) {
  268.     goto done;
  269.     }
  270.     if (lateRecs > 0) {
  271.     size = lateRecs * traceHdrPtr->dataSize;
  272.     status = Vm_CopyOut(size, (Address)
  273.                   traceHdrPtr->recordArray[current].traceData,
  274.                 addr);
  275.     if (status != SUCCESS) {
  276.         goto done;
  277.     }
  278.     addr += size;
  279.     }
  280.     if (earlyRecs > 0) {
  281.     size = earlyRecs * traceHdrPtr->dataSize;
  282.     status = Vm_CopyOut(size,
  283.                 (Address) traceHdrPtr->recordArray[0].traceData,
  284.                 addr);
  285.     if (status != SUCCESS) {
  286.         goto done;
  287.     }
  288.     addr += size;
  289.     }
  290.  
  291. done:
  292.     traceHdrPtr->flags &= ~TRACE_INHIBIT;
  293.     return(SUCCESS);
  294.     
  295. }
  296.  
  297. /*
  298.  *----------------------------------------------------------------------
  299.  *
  300.  * Trace_Print --
  301.  *
  302.  *    Print trace records using a client's printing procedure to
  303.  *    format the client data.  The N most recent records are displayed.
  304.  *    The interface to the printing procedure is:
  305.  *    (*printRecord)(clientData, printHeaderFlag)
  306.  *        ClientData clientData;
  307.  *        Boolean printHeaderFlag;
  308.  *    where the flag should cause column headers to be printed.
  309.  *    Careful, ClientData might be NIL if the flag is TRUE.
  310.  *
  311.  * Results:
  312.  *    None
  313.  *
  314.  * Side effects:
  315.  *    prints to the screen.
  316.  *
  317.  *----------------------------------------------------------------------
  318.  */
  319.  
  320. ReturnStatus
  321. Trace_Print(traceHdrPtr, numRecs, printProc)
  322.     register Trace_Header *traceHdrPtr;    /* Trace record */
  323.     int numRecs;        /* Number of most recent records to print */
  324.     int (*printProc)();        /* See above doc. for this call-back */
  325. {
  326.     register int traceLength;
  327. /*    int lastRec; */        /* Index of last record to be printed */
  328. /*    int firstRec; */        /* Index of first record to be printed */
  329.     int index;
  330. /*    Boolean printHeader; */    /* Passed to output routine */
  331.     Time deltaTime;        /* Time difference between trace records */
  332.     Time baseTime;        /* Used to calculate deltaTime */
  333.     Trace_Record *recordPtr;
  334.  
  335.     if (trace_Disable) {
  336.     (*printProc)((ClientData *)NIL, TRUE);
  337.     printf("All Tracing Disabled.\n");
  338.     return SUCCESS;
  339.     }
  340.  
  341.     MASTER_LOCK(&trace_Mutex);
  342.     traceHdrPtr->flags |= TRACE_INHIBIT;
  343.     MASTER_UNLOCK(&trace_Mutex);
  344.  
  345.     baseTime.seconds = 0;
  346.     baseTime.microseconds = 0;
  347.     /*
  348.      * Print the header.
  349.      * Loop through the records starting numRecs modulo-before the end.
  350.      * Print the header.
  351.      */
  352.     (*printProc)((ClientData *)NIL, TRUE);
  353.     traceLength = traceHdrPtr->numRecords;
  354.     if (numRecs > traceLength) {
  355.     numRecs = traceLength;
  356.     }
  357.     index = (traceHdrPtr->currentRecord - numRecs + traceLength)
  358.         % traceLength;
  359.     for ( ; numRecs > 0; numRecs--, index = (index + 1) % traceLength) {
  360.     recordPtr = &traceHdrPtr->recordArray[index];
  361.     if (recordPtr->flags & TRACE_UNUSED) {
  362.         continue;
  363.     }
  364.     if ( ! (traceHdrPtr->flags & TRACE_NO_TIMES)) {
  365.         Time_Subtract(recordPtr->time, baseTime, &deltaTime);
  366.         if (baseTime.seconds + baseTime.microseconds > 0) {
  367.         printf("%2d.%04d ", deltaTime.seconds,
  368.                     deltaTime.microseconds / 100);
  369.         } else {
  370.         printf("           ");
  371.         }
  372.         baseTime = recordPtr->time;
  373.     }
  374.     (*printProc)(recordPtr->traceData, recordPtr->event, FALSE);
  375.     printf("\n");
  376.     }
  377.     (*printProc)((ClientData *)NIL, TRUE);
  378.  
  379.     traceHdrPtr->flags &= ~TRACE_INHIBIT;
  380.     return(SUCCESS);
  381. }
  382.  
  383.